/**
 * @file QWF_Can.c
 * @brief QWF框架CAN总线通信模块（实现CAN控制器初始化、过滤器配置及基础数据发送功能）
 * @details 支持双CAN控制器（CAN1/CAN2），兼容DJI设备通信协议（预定义标准ID如0x200、0x1ff等），
 *          包含过滤器初始化、总线启动及中断通知激活功能。
 * @author WeiFan Qiu (qiuweifan0523@faxmail.com)
 * @version 1.0
 * @date 2025-08-07
 * 
 * @copyright Copyright (c) 2025 邱伟凡
 * 
 * @par 修改日志:
 * - 2025-08-07: 初始版本，定义CAN通信结构体、过滤器初始化及基础发送功能
 * - 2025-08-09: 加入适配fdcan代码，待实机测试
 * @bug 待解决问题: 暂无已知问题
 */
#include "QWF_Ctrl.h"

/**
 * @brief QWF框架CAN通信全局结构体（存储双CAN控制器配置及运行状态）
 * @note 内存对齐1字节（适配部分嵌入式系统严格对齐要求）
 */
__align(1) QWF_CAN_t QWF_CAN={
	.can1={
		.hcan=&get_can_type(h,can1),  // 指向CAN1硬件句柄
		.tx={
			.header={
				.DJI={
					/**
					 * @brief DJI设备标准发送帧头（适配RM系列电机、电调）
					 * @note 包含5组常用ID（0x200/0x1ff/0x2ff/0x1fe/0x2fe），
					 *       对应不同设备类型（如驱动电机、舵机）
					 */
					.id200={.can_stdld=0x200,},
					.id1ff={.can_stdld=0x1ff,},
					.id2ff={.can_stdld=0x2ff,},
					.id1fe={.can_stdld=0x1fe,},
					.id2fe={.can_stdld=0x2fe,},
				},
			},
			.mailbox={
				.DJI={			// DJI设备发送邮箱状态（记录当前使用的发送邮箱索引）
					.id200=0,	// ID=0x200对应的邮箱号（0/1/2）
					.id1ff=0,
					.id2ff=0,
					.id1fe=0,
					.id2fe=0,
				},
			},
		},
		.rx={0
			
		},
	},
	.can2={
		.hcan=&get_can_type(h,can2),  // 指向CAN2硬件句柄（配置同CAN1）
		.tx={
			.header={
				.DJI={
					.id200.can_stdld=0x200,
					.id1ff.can_stdld=0x1ff,
					.id2ff.can_stdld=0x2ff,
					.id1fe.can_stdld=0x1fe,
					.id2fe.can_stdld=0x2fe,
				},
			},
			.mailbox={
				.DJI={
					.id200=0,
					.id1ff=0,
					.id2ff=0,
					.id1fe=0,
					.id2fe=0,
				},
			},
		},
		.rx={0
			
		},
	},
	#if Chip_Type==Chip_STM32H723VGT6
	.can3={
		.hcan=&get_can_type(h,can3),  // 指向CAN2硬件句柄（配置同CAN1）
		.tx={
			.header={
				.DJI={
					.id200.can_stdld=0x200,
					.id1ff.can_stdld=0x1ff,
					.id2ff.can_stdld=0x2ff,
					.id1fe.can_stdld=0x1fe,
					.id2fe.can_stdld=0x2fe,
				},
			},
			.mailbox={
				.DJI={
					.id200=0,
					.id1ff=0,
					.id2ff=0,
					.id1fe=0,
					.id2fe=0,
				},
			},
		},
		.rx={
			
		},
	},	
	#endif
};

/**
 * @brief QWF_CAN结构体全局指针（外部模块通过此指针访问CAN配置）
 * @note 避免直接操作全局变量，提高代码封装性
 */
QWF_CAN_t* qwf_can=&QWF_CAN;
static void can_txheader_standard_init(GET_CAN_TYPE( ,CAN_TxHeaderTypeDef)* txheader){
#if Chip_Type==Chip_STM32F405RGT6
	txheader->ExtId=0;
	txheader->IDE=CAN_ID_STD;
	txheader->RTR=CAN_RTR_DATA;
	txheader->DLC=0X08;
	txheader->TransmitGlobalTime=DISABLE;
#elif Chip_Type==Chip_STM32H723VGT6
	txheader->IdType = FDCAN_STANDARD_ID;
	txheader->TxFrameType = FDCAN_DATA_FRAME;
	txheader->DataLength = 8;
	txheader->ErrorStateIndicator =  FDCAN_ESI_ACTIVE;
	txheader->BitRateSwitch = FDCAN_BRS_OFF;
	txheader->FDFormat =  FDCAN_CLASSIC_CAN;           
	txheader->TxEventFifoControl =  FDCAN_NO_TX_EVENTS;  
	txheader->MessageMarker = 0;
#endif
}

/**
 * @brief 初始化CAN过滤器及中断（关键通信配置函数）
 * @param hcan 目标CAN控制器句柄（&hcan1或&hcan2或者&hcan3）get_qwf_can_hcan(x)
 * @details 配置为32位掩码模式，过滤所有ID（掩码全0），适用于设备较少的场景；
 *          激活FIFO0中断，用于接收数据。
 * @note 不同CAN控制器使用不同的过滤器组（CAN1用FilterBank 1，CAN2用14），避免冲突
 */
static void can_fifo_init(GET_CAN_TYPE( ,CAN_HandleTypeDef)* handle){//can过滤器初始化
	#if Chip_Type==Chip_STM32F405RGT6
	CAN_FilterTypeDef can_filter_st;//过滤器配置结构体
    can_filter_st.FilterActivation = ENABLE;  // 启用过滤器
    can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK;  // 掩码模式（ID+掩码匹配）
    can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT;  // 32位过滤精度
    can_filter_st.FilterIdHigh = 0x0000;  // 待匹配ID高16位（全0表示任意ID）
    can_filter_st.FilterIdLow = 0x0000;   // 待匹配ID低16位（全0表示任意ID）
    can_filter_st.FilterMaskIdHigh = 0x0000;  // 掩码高16位（全0表示不限制）
    can_filter_st.FilterMaskIdLow = 0x0000;   // 掩码低16位（全0表示不限制）

	// 根据目标CAN控制器选择过滤器组（STM32双CAN共享过滤器组，需分配不同Bank）
	if(handle==&hcan1)
		can_filter_st.FilterBank = 1;  // CAN1使用过滤器组1
	else if(handle==&hcan2)
	 	can_filter_st.FilterBank = 14; // CAN2使用过滤器组14

    can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0;  // 接收数据存入FIFO0
	can_filter_st.SlaveStartFilterBank=14;  // 从CAN（如果有）起始过滤器组

    HAL_CAN_ConfigFilter(handle, &can_filter_st);  // 应用过滤器配置
	HAL_CAN_Start(handle);  // 启动CAN总线通信
    HAL_CAN_ActivateNotification(handle, CAN_IT_RX_FIFO0_MSG_PENDING);  // 激活FIFO0消息挂起中断
	#elif Chip_Type==Chip_STM32H723VGT6
	FDCAN_FilterTypeDef FDCAN_FilterConfig;
	
  FDCAN_FilterConfig.IdType = FDCAN_STANDARD_ID; // 过滤ID类型选择 标准ID
  FDCAN_FilterConfig.FilterIndex = 0;           //当前FDCAN过滤器编号，可以设置多个过滤器过滤不同的ID 依次类推0、1、2....
  FDCAN_FilterConfig.FilterType = FDCAN_FILTER_MASK; //过滤器Mask模式 关乎到下面ID1、ID2的配置
  FDCAN_FilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;//选择哪个FIFO区接收，根据CubeMX的配置来，FIFO1就改成FDCAN_FILTER_TO_RXFIFO1
  FDCAN_FilterConfig.FilterID1 = 0x00000000; // 这个都行，只要ID2配置0x00000000就不会过滤调任何ID
  FDCAN_FilterConfig.FilterID2 = 0x00000000; //理由如上
  
  HAL_FDCAN_ConfigFilter(handle, &FDCAN_FilterConfig); //将上述配置到CAN1
		
  HAL_FDCAN_ConfigGlobalFilter(handle, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE); //开启CAN1的全局过滤，就是开启过滤器
 if(handle==&hfdcan1){
	HAL_FDCAN_ActivateNotification(handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);//打开FIFO0区的新数据接收中断	
 }
 else if(handle==&hfdcan2){
	
 }
	#endif
}													

/**
 * @brief 初始化所有CAN控制器（系统级初始化函数）
 * @details 调用can_fifo_init分别初始化CAN1和CAN2，完成总线启动和中断配置
 * @note 需在系统初始化阶段调用（如main函数开头），确保CAN通信就绪
 */
void Can_Init(void){//初始化
	can_txheader_standard_init(&qwf_can->can1.tx.header.DJI.id1fe);
	can_txheader_standard_init(&qwf_can->can1.tx.header.DJI.id1ff);
	can_txheader_standard_init(&qwf_can->can1.tx.header.DJI.id200);
	can_txheader_standard_init(&qwf_can->can1.tx.header.DJI.id2fe);
	can_txheader_standard_init(&qwf_can->can1.tx.header.DJI.id2ff);
	can_fifo_init(&get_can_type( h,can1));  // 初始化CAN1
	
	can_txheader_standard_init(&qwf_can->can2.tx.header.DJI.id1fe);
	can_txheader_standard_init(&qwf_can->can2.tx.header.DJI.id1ff);
	can_txheader_standard_init(&qwf_can->can2.tx.header.DJI.id200);
	can_txheader_standard_init(&qwf_can->can2.tx.header.DJI.id2fe);
	can_txheader_standard_init(&qwf_can->can2.tx.header.DJI.id2ff);	
	can_fifo_init(&get_can_type( h,can2));  // 初始化CAN2
	#if Chip_Type==Chip_STM32H723VGT6
	can_txheader_standard_init(&qwf_can->can3.tx.header.DJI.id1fe);
	can_txheader_standard_init(&qwf_can->can3.tx.header.DJI.id1ff);
	can_txheader_standard_init(&qwf_can->can3.tx.header.DJI.id200);
	can_txheader_standard_init(&qwf_can->can3.tx.header.DJI.id2fe);
	can_txheader_standard_init(&qwf_can->can3.tx.header.DJI.id2ff);		
	#endif
}
/**
 * @brief CAN周期性发送任务（统一处理双CAN控制器的标准ID数据发送）
 * @param argument 任务参数（未使用，FreeRTOS任务要求）
 * @details 周期1ms执行，检查CAN1/CAN2的预定义DJI设备ID（如0x200、0x1ff）是否有数据待发送，
 *          若有则调用HAL库函数添加到发送邮箱。
 * @note 需配合FreeRTOS调度，确保实时性；通过`get_qwf_can_tx_StdId_use`判断是否启用对应ID的发送。
 */
void can_tx_task(void const * argument){
	static TickType_t xLastWakeTime;
    const TickType_t xPeriod = pdMS_TO_TICKS(1);// 任务周期：1ms（确保电机控制指令实时性）
    // 初始化任务唤醒时间（用于vTaskDelayUntil保持严格周期）
    xLastWakeTime = xTaskGetTickCount();
	Can_Init();
	Motor_Init();
	while(1){
	/********************************CAN1数据发送*************************/
		// 检查并发送CAN1的0x200 ID数据
		if(get_qwf_can_tx_StdId_use(1,DJI.id200))
			can_add_tx_message(&get_can_type( h,can1),&get_qwf_can_tx_header(1,DJI.id200),&get_qwf_can_data_tx(1,DJI.id200)[0],&get_qwf_can_mailbox(1,DJI.id200));
		// 检查并发送CAN1的0x1ff ID数据
		if(get_qwf_can_tx_StdId_use(1,DJI.id1ff))			
			can_add_tx_message(&get_can_type( h,can1),&get_qwf_can_tx_header(1,DJI.id1ff),&get_qwf_can_data_tx(1,DJI.id1ff)[0],&get_qwf_can_mailbox(1,DJI.id1ff));
		// 检查并发送CAN1的0x2ff ID数据
		if(get_qwf_can_tx_StdId_use(1,DJI.id2ff))			
			can_add_tx_message(&get_can_type( h,can1),&get_qwf_can_tx_header(1,DJI.id2ff),&get_qwf_can_data_tx(1,DJI.id2ff)[0],&get_qwf_can_mailbox(1,DJI.id2ff));
		// 检查并发送CAN1的0x1fe ID数据
		if(get_qwf_can_tx_StdId_use(1,DJI.id1fe))			
			can_add_tx_message(&get_can_type( h,can1),&get_qwf_can_tx_header(1,DJI.id1fe),&get_qwf_can_data_tx(1,DJI.id1fe)[0],&get_qwf_can_mailbox(1,DJI.id1fe));
		// 检查并发送CAN1的0x2fe ID数据
		if(get_qwf_can_tx_StdId_use(1,DJI.id2fe))			
			can_add_tx_message(&get_can_type( h,can1),&get_qwf_can_tx_header(1,DJI.id2fe),&get_qwf_can_data_tx(1,DJI.id2fe)[0],&get_qwf_can_mailbox(1,DJI.id2fe));	
		/********************************CAN2数据发送*************************/                                
		// 检查并发送CAN2的0x200 ID数据
		if(get_qwf_can_tx_StdId_use(2,DJI.id200))			                                                    
			can_add_tx_message(&get_can_type( h,can2),&get_qwf_can_tx_header(2,DJI.id200),&get_qwf_can_data_tx(2,DJI.id200)[0],&get_qwf_can_mailbox(2,DJI.id200));
		// 检查并发送CAN2的0x1ff ID数据
		if(get_qwf_can_tx_StdId_use(2,DJI.id1ff))																											
			can_add_tx_message(&get_can_type( h,can2),&get_qwf_can_tx_header(2,DJI.id1ff),&get_qwf_can_data_tx(2,DJI.id1ff)[0],&get_qwf_can_mailbox(2,DJI.id1ff));
		// 检查并发送CAN2的0x2ff ID数据
		if(get_qwf_can_tx_StdId_use(2,DJI.id2ff))			
			can_add_tx_message(&get_can_type( h,can2),&get_qwf_can_tx_header(2,DJI.id2ff),&get_qwf_can_data_tx(2,DJI.id2ff)[0],&get_qwf_can_mailbox(2,DJI.id2ff));
		// 检查并发送CAN2的0x1fe ID数据
		if(get_qwf_can_tx_StdId_use(2,DJI.id1fe))																											
			can_add_tx_message(&get_can_type( h,can2),&get_qwf_can_tx_header(2,DJI.id1fe),&get_qwf_can_data_tx(2,DJI.id1fe)[0],&get_qwf_can_mailbox(2,DJI.id1fe));
		// 检查并发送CAN2的0x2fe ID数据
		if(get_qwf_can_tx_StdId_use(2,DJI.id2fe))			
			can_add_tx_message(&get_can_type( h,can2),&get_qwf_can_tx_header(2,DJI.id2fe),&get_qwf_can_data_tx(2,DJI.id2fe)[0],&get_qwf_can_mailbox(2,DJI.id2fe));			
		vTaskDelayUntil(&xLastWakeTime, xPeriod);	
	}
}

/**
 * @brief 通用CAN数据发送函数（支持自定义ID和数据）
 * @param StdId 发送帧的标准ID（0-0x7FF）
 * @param Mailbox 目标发送邮箱（0-2，由硬件分配）
 * @param Data 待发送的数据数组（最多8字节，符合CAN协议DLC=8）
 * @param hcan 目标CAN控制器句柄（&hcan1或&hcan2）
 * @details 固定配置为标准ID、数据帧、8字节长度，适用于非DJI协议的自定义设备通信。
 * @note 若需扩展ID或其他格式，需修改`CanTx`结构体配置。
 */
void Can_Send_Data(uint32_t StdId,uint32_t Mailbox ,uint8_t Data[8],GET_CAN_TYPE( ,CAN_HandleTypeDef)*hcan)
{
	GET_CAN_TYPE( ,CAN_TxHeaderTypeDef) CanTx;
	can_txheader_standard_init(&CanTx);	
	// 调用HAL库函数添加发送消息到指定邮箱
	can_add_tx_message(hcan, &CanTx, Data, &Mailbox);
}

/**
 * @brief HAL库CAN接收FIFO0消息挂起回调函数（硬件中断触发）
 * @param hcan 触发中断的CAN控制器句柄
 * @details 当CAN控制器的FIFO0有新消息时自动调用，根据CAN实例（CAN1/CAN2）读取数据，
 *          并根据接收的标准ID调用对应设备的解析函数（如电机数据、IMU数据）。
 * @note 需在CubeMX中启用`CAN_IT_RX_FIFO0_MSG_PENDING`中断使能。
 */
#if Chip_Type==Chip_STM32F405RGT6
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* get_can_type(h,can))
#elif Chip_Type==Chip_STM32H723VGT6
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *get_can_type(h,can), uint32_t RxFifo0ITs)
#endif	
{
if(get_can_type(h,can)==&get_can_type(h,can1)){	// CAN1接收处理
		// 获取接收消息（存储到QWF_CAN结构体的rx缓冲区）
		GET_CAN_TYPE(HAL_,CAN_GetRxMessage)(get_can_type(h,can), GET_CAN_TYPE( ,CAN_RX_FIFO0), &get_qwf_can_rx_can(1), get_qwf_can_data_rx(1));
		// 根据接收的标准ID分发处理（适配不同设备）
		switch(get_qwf_can_rx_can(1).can_stdld){
		#if Circuit_Boards!=Chassis_Circuit_Boards		
			case (0x204+pitch_id):		DJI_Motor_return[without_round]							(&head->part.gimbal.pitch.motor		,get_qwf_can_data_rx(1)		);qwf_state->head.motor.gimbal.pitch.online.tick=qwf_state->sys_tick;break;
			case (0x200+fire_l_id):		DJI_Motor_return[head->part.shoot.fire.l.motor.rx_meas.flag]	(&head->part.shoot.fire.l.motor		,get_qwf_can_data_rx(1)		);qwf_state->head.motor.shoot.fire.l.online.tick=qwf_state->sys_tick;break;
			case (0x200+fire_r_id):		DJI_Motor_return[head->part.shoot.fire.r.motor.rx_meas.flag]	(&head->part.shoot.fire.r.motor		,get_qwf_can_data_rx(1)		);qwf_state->head.motor.shoot.fire.r.online.tick=qwf_state->sys_tick;break;
			case (dm_imu_rx_id):
					DM_IMU_UpdateData(get_qwf_can_data_rx(1));
			break;
		#endif			
		#if Circuit_Boards!=Head_Circuit_Boards	
			#if Chassis_Wheel_Type==Helf_Helm_Wheel
			case (0x200+l_wheel_id):		DJI_Motor_return[without_round]			(&chassis->part.l.wheel.motor			,get_qwf_can_data_rx(1)	);qwf_state->chassis.motor.l.wheel.online.tick=qwf_state->sys_tick;break;
			case (0x200+r_wheel_id):		DJI_Motor_return[without_round]			(&chassis->part.r.wheel.motor			,get_qwf_can_data_rx(1)	);qwf_state->chassis.motor.r.wheel.online.tick=qwf_state->sys_tick;break;
			case (0x200+f_wheel_id):		DJI_Motor_return[without_round]			(&chassis->part.f.wheel.motor			,get_qwf_can_data_rx(1)		);qwf_state->chassis.motor.f.wheel.online.tick=qwf_state->sys_tick;break;
			case (0x200+b_wheel_id):		DJI_Motor_return[without_round]			(&chassis->part.b.wheel.motor			,get_qwf_can_data_rx(1)	);qwf_state->chassis.motor.b.wheel.online.tick=qwf_state->sys_tick;break;	
			case (0x204+f_helm_id):			DJI_Motor_return[without_round]			(&chassis->part.f.helm.motor		,get_qwf_can_data_rx(1)			);qwf_state->chassis.motor.f.helm.online.tick=qwf_state->sys_tick;break;
			case (0x204+b_helm_id):			DJI_Motor_return[without_round]			(&chassis->part.b.helm.motor		,get_qwf_can_data_rx(1)			);qwf_state->chassis.motor.b.helm.online.tick=qwf_state->sys_tick;break;
//			case 0x213:
//				power_get_func( QWF_CAN[1-1]->data_rx);
//			break;
			#elif Chassis_Wheel_Type==Leg_Wheel
			
			#endif
		#endif			
		}	
	}
	if(get_can_type(h,can)==&get_can_type(h,can2)){//can2
		GET_CAN_TYPE(HAL_,CAN_GetRxMessage)(get_can_type(h,can), GET_CAN_TYPE( ,CAN_RX_FIFO0),&get_qwf_can_rx_can(2), get_qwf_can_data_rx(2));
		switch(get_qwf_can_rx_can(2).can_stdld){
		#if Circuit_Boards!=Chassis_Circuit_Boards		
			case (0x204+yaw_id):		DJI_Motor_return[without_round]							(&head->part.gimbal.yaw.motor		,get_qwf_can_data_rx(2)	);qwf_state->head.motor.gimbal.yaw.online.tick=qwf_state->sys_tick;break;
			case (0x200+knob_id):		DJI_Motor_return[head->part.shoot.knob.motor.rx_meas.flag]	(&head->part.shoot.knob.motor		,get_qwf_can_data_rx(2)	);qwf_state->head.motor.shoot.knob.online.tick=qwf_state->sys_tick;break;
			case (0x666):comunicate_cal((communicate_rx_t*)get_qwf_can_data_rx(2)	);break;
		#endif			
		#if Circuit_Boards!=Head_Circuit_Boards		
			case 0x211:
				super_elec_rx_func(get_qwf_can_data_rx(2));qwf_state->chassis.super_elec.online.tick=qwf_state->sys_tick;
			break;			
//						case (dm_imu_rx_id):DM_IMU_UpdateData(get_qwf_can_data_rx(2));break;
			case (0x204+yaw_id):				
				DJI_Motor_return[without_round]			(&chassis->part.yaw.motor					,get_qwf_can_data_rx(2)	);qwf_state->head.motor.gimbal.yaw.online.tick=qwf_state->sys_tick;break;					
			case(0x666):comunicate_cal((communicate_rx_t*)get_qwf_can_data_rx(2));break;
		#endif			
		}	
	}
	#if Chip_Type==Chip_STM32F405RGT6
	__HAL_CAN_ENABLE_IT(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
	#endif
}
